#!/usr/bin/env python3
###
# @Author: Logan.Li
# @Gitee: https://gitee.com/attacker
# @email: admin@attacker.club
# @Date: 2025-03-14 08:20:30
# @LastEditTime: 2025-03-14 08:20:35
# @Description: 华为云监控告警脚本
###

import os
import sys
import json
import time
import logging
from datetime import datetime, timedelta
import configparser
from huaweicloudsdkcore.auth.credentials import BasicCredentials
from huaweicloudsdkces.v1.region.ces_region import CesRegion
from huaweicloudsdkcore.exceptions import exceptions
from huaweicloudsdkces.v1 import *

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('huaweicloud_monitor.log'),
        logging.StreamHandler()
    ]
)

class HuaweiCloudMonitor:
    def __init__(self, config_file='config.ini'):
        """初始化华为云监控客户端"""
        self.config = self._load_config(config_file)
        self.client = self._init_client()
        
    def _load_config(self, config_file):
        """加载配置文件"""
        if not os.path.exists(config_file):
            logging.error(f"配置文件不存在: {config_file}")
            sys.exit(1)
            
        config = configparser.ConfigParser()
        config.read(config_file)
        
        if 'huaweicloud' not in config:
            logging.error("配置文件中缺少 [huaweicloud] 部分")
            sys.exit(1)
            
        return config['huaweicloud']
        
    def _init_client(self):
        """初始化华为云客户端"""
        try:
            credentials = BasicCredentials(
                self.config['ak'],
                self.config['sk']
            )
            
            return CesClient.new_builder() \
                .with_credentials(credentials) \
                .with_region(CesRegion.value_of(self.config['region'])) \
                .build()
                
        except exceptions.ClientRequestException as e:
            logging.error(f"初始化客户端失败: {e}")
            sys.exit(1)
            
    def get_metrics(self, namespace, metric_name, dimensions, period=300):
        """获取指定指标的监控数据
        
        Args:
            namespace: 指标命名空间，如 'SYS.ECS'
            metric_name: 指标名称，如 'cpu_util'
            dimensions: 维度列表，如 [{"name": "instance_id", "value": "xxx"}]
            period: 监控周期（秒），默认300秒
        """
        try:
            now = datetime.utcnow()
            request = ShowMetricDataRequest(
                namespace=namespace,
                metric_name=metric_name,
                dim_0=json.dumps(dimensions[0]),
                period=period,
                from_=int(time.mktime((now - timedelta(hours=1)).timetuple()) * 1000),
                to=int(time.mktime(now.timetuple()) * 1000)
            )
            
            response = self.client.show_metric_data(request)
            return response.to_dict()
            
        except exceptions.ClientRequestException as e:
            logging.error(f"获取监控数据失败: {e}")
            return None
            
    def create_alarm(self, alarm_name, namespace, metric_name, dimensions, 
                    threshold, comparison_operator=">=", period=300,
                    evaluation_periods=3, alarm_actions=None):
        """创建告警规则
        
        Args:
            alarm_name: 告警规则名称
            namespace: 指标命名空间
            metric_name: 指标名称
            dimensions: 维度列表
            threshold: 阈值
            comparison_operator: 比较运算符，默认 '>='
            period: 监控周期（秒），默认300秒
            evaluation_periods: 连续周期数，默认3
            alarm_actions: 告警动作列表
        """
        try:
            metric = MetricInfo(
                namespace=namespace,
                metric_name=metric_name,
                dimensions=dimensions
            )
            
            condition = AlarmCondition(
                period=period,
                filter="average",
                comparison_operator=comparison_operator,
                value=threshold,
                unit="%",
                count=evaluation_periods
            )
            
            request = CreateAlarmRequest(
                alarm_name=alarm_name,
                alarm_description=f"Auto created alarm for {metric_name}",
                metric=metric,
                condition=condition,
                alarm_actions=alarm_actions or [],
                alarm_enabled=True
            )
            
            response = self.client.create_alarm(request)
            logging.info(f"成功创建告警规则: {alarm_name}")
            return response.to_dict()
            
        except exceptions.ClientRequestException as e:
            logging.error(f"创建告警规则失败: {e}")
            return None
            
    def list_alarms(self, limit=100):
        """列出所有告警规则"""
        try:
            request = ListAlarmRequest(
                limit=limit
            )
            
            response = self.client.list_alarm(request)
            return response.to_dict()
            
        except exceptions.ClientRequestException as e:
            logging.error(f"获取告警规则列表失败: {e}")
            return None

def main():
    """主函数"""
    try:
        monitor = HuaweiCloudMonitor()
        
        # 示例：获取ECS实例CPU使用率
        metrics = monitor.get_metrics(
            namespace='SYS.ECS',
            metric_name='cpu_util',
            dimensions=[{
                "name": "instance_id",
                "value": "your-instance-id"
            }]
        )
        logging.info(f"CPU使用率: {metrics}")
        
        # 示例：创建CPU使用率告警
        alarm = monitor.create_alarm(
            alarm_name="CPU使用率告警",
            namespace="SYS.ECS",
            metric_name="cpu_util",
            dimensions=[{
                "name": "instance_id",
                "value": "your-instance-id"
            }],
            threshold=80,
            comparison_operator=">=",
            period=300,
            evaluation_periods=3,
            alarm_actions=[{
                "type": "notification",
                "notificationList": ["your-topic-urn"]
            }]
        )
        logging.info(f"创建告警结果: {alarm}")
        
    except Exception as e:
        logging.error(f"发生错误: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()
